﻿using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Naruto.Redis.Config;
using Naruto.Redis.Interface;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Naruto.Redis
{
    /// <summary>
    /// 连接工厂
    /// </summary>
    public class RedLockConnectionFactory : IRedLockConnectionFactory
    {
        /// <summary>
        /// 连接
        /// </summary>
        private List<ConnectionMultiplexer> _connectionMultiplexers;

        /// <summary>
        /// 锁
        /// </summary>
        private readonly SemaphoreSlim _lockConnection = new SemaphoreSlim(1);

        /// <summary>
        /// 配置
        /// </summary>
        private readonly IOptions<RedisOptions> _options;
        /// <summary>
        ///日志
        /// </summary>
        private readonly ILogger<RedLockConnectionFactory> _logger;
        /// <summary>
        /// 
        /// </summary>
        public RedLockConnectionFactory(IOptions<RedisOptions> options, ILogger<RedLockConnectionFactory> logger)
        {
            _options = options;
            _logger = logger;
        }
        /// <summary>
        /// 创建连接
        /// </summary>
        /// <returns></returns>
        public async Task<List<ConnectionMultiplexer>> CreateConnectionAsync()
        {
            if (_connectionMultiplexers != null && _connectionMultiplexers.Count > 0)
            {
                return _connectionMultiplexers;
            }
            await _lockConnection.WaitAsync();
            try
            {
                if (_connectionMultiplexers != null && _connectionMultiplexers.Count > 0)
                {
                    return _connectionMultiplexers;
                }
                _logger.LogTrace("开始初始化 redlock锁连接");
                //初始化
                _connectionMultiplexers = new List<ConnectionMultiplexer>();
                if (_options.Value.Connection == null || _options.Value.Connection.Length <= 0)
                {
                    throw new ArgumentNullException("请填写有效的redis连接字符串,Connection");
                }
                //连接
                foreach (var item in _options.Value.Connection)
                {
                    var configurationOptions = new ConfigurationOptions();
                    configurationOptions.EndPoints.Add(item);
                    configurationOptions.Password = _options.Value.Password ?? "";
                    configurationOptions.AbortOnConnectFail = false;
                    _connectionMultiplexers.Add(await ConnectionMultiplexer.ConnectAsync(configurationOptions));
                }
                _logger.LogTrace("初始化完毕");
                return _connectionMultiplexers;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "创建连接失败");
                throw;
            }
            finally
            {
                _lockConnection.Release();
            }
        }

        public void Dispose()
        {
            Dispose(true);
        }

        protected virtual void Dispose(bool isDispose)
        {
            if (isDispose)
            {
                if (_connectionMultiplexers != null)
                {
                    foreach (var item in _connectionMultiplexers)
                    {
                        item.Dispose();
                    }
                    _connectionMultiplexers = null;
                }
                GC.SuppressFinalize(this);
            }
        }
    }
}
